﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using Struct = System.Decimal;

namespace ArgusPCLib.Mathematics
{
	public struct DecimalWrapper : ILinearScalar
	{
		Struct _value;

		public DecimalWrapper(Struct value)
		{
			this._value = value;
		}

		public static implicit operator DecimalWrapper(Struct value)
		{
			return new DecimalWrapper(value);
		}

		public static implicit operator Struct(DecimalWrapper value)
		{
			return value._value;
		}

		#region IOperand
		public static DecimalWrapper Parse(string text, string format, IFormatProvider formatProvider)
		{
			
			if (typeof(Struct) != typeof(int))
				throw new Exception("Please customize the templated code...");
			NumberStyles numberStyle;
			if (format != null && format.ToLowerInvariant().StartsWith("h"))
				numberStyle = NumberStyles.HexNumber;
			else
				numberStyle = NumberStyles.Integer;
			return Struct.Parse(text, numberStyle, formatProvider);
		}

		public static bool TryParse(string text, string format, IFormatProvider formatProvider, out DecimalWrapper value)
		{
			if (typeof(Struct) != typeof(int))
				throw new Exception("Please customize the templated code...");
			NumberStyles numberStyle;
			if (format != null && format.ToLowerInvariant().StartsWith("h"))
				numberStyle = NumberStyles.HexNumber;
			else
				numberStyle = NumberStyles.Integer;
			Struct result;
			if (Struct.TryParse(text, numberStyle, formatProvider, out result))
			{
				value = new DecimalWrapper(result);
				return true;
			}
			else
			{
				value = new DecimalWrapper();
				return false;
			}
		}

		public static int PartialParse(string text, string format, IFormatProvider formatProvider, out DecimalWrapper value)
		{
			if (typeof(Struct) != typeof(int))
				throw new Exception("Please customize the templated code...");
			int start;
			for (start = 0; start < text.Length; start++)
			{
				if (!char.IsWhiteSpace(text[start]))
					break;
			}

			NumberFormatInfo nfi = (NumberFormatInfo)formatProvider;

			NumberStyles numberStyle;
			if (format != null && format.ToLowerInvariant().StartsWith("h"))
				numberStyle = NumberStyles.HexNumber;
			else
				numberStyle = NumberStyles.Integer;

			int start2 = start;
			if (text.Substring(start, nfi.NegativeSign.Length) == nfi.NegativeSign)
			{
				start2 = start2 + nfi.NegativeSign.Length;
			}
			int end;
			for (end = start2; end < text.Length; end++)
			{
				if (char.IsNumber(text[end]))
					continue;
				if (numberStyle == NumberStyles.HexNumber)
				{
					char c = char.ToLowerInvariant(text[end]);
					if (c >= 'a' && c <= 'f')
						continue;
				}
				break;
			}

			if (end - start < 1)
			{
				value = new DecimalWrapper();
				return -1;
			}

			value = new DecimalWrapper(Struct.Parse(text.Substring(start, end - start), numberStyle, formatProvider));
			return end;
		}

		IOperand IOperand.GetDeepCopy() { return new DecimalWrapper(this._value); }
		#endregion

		#region IFormattable
		public string ToString(string format, IFormatProvider formatProvider)
		{
			return this._value.ToString(format, formatProvider);
		}

		public override string ToString()
		{
			return this.ToString(null, null);
		}
		#endregion

		#region IScalar
		public static DecimalWrapper Zero { get { return new DecimalWrapper(0); } }
		public static DecimalWrapper One { get { return new DecimalWrapper(1); } }

		public static DecimalWrapper operator +(DecimalWrapper a, DecimalWrapper b)
		{
			return new DecimalWrapper(a._value + b._value);
		}

		public static DecimalWrapper operator -(DecimalWrapper a, DecimalWrapper b)
		{
			return new DecimalWrapper(a._value - b._value);
		}

		public static DecimalWrapper operator *(DecimalWrapper a, DecimalWrapper b)
		{
			return new DecimalWrapper(a._value * b._value);
		}

		public static DecimalWrapper operator /(DecimalWrapper a, DecimalWrapper b)
		{
			return new DecimalWrapper(a._value / b._value);
		}

		public static bool operator ==(DecimalWrapper a, DecimalWrapper b)
		{
			return a._value == b._value;
		}

		public static bool operator !=(DecimalWrapper a, DecimalWrapper b)
		{
			return a._value != b._value;
		}

		IScalar IScalar.Add(IScalar value) { return this + (DecimalWrapper)value; }
		IScalar IScalar.Multiply(IScalar value) { return this * (DecimalWrapper)value; }
		IScalar IScalar.Subtract(IScalar value) { return this - (DecimalWrapper)value; }
		IScalar IScalar.Divide(IScalar value) { return this / (DecimalWrapper)value; }
		bool IScalar.IsEqualTo(IScalar value) { return this == (DecimalWrapper)value; }
		#endregion

		#region ILinearScalar
		public static bool operator <(DecimalWrapper a, DecimalWrapper b)
		{
			return a._value < b._value;
		}

		public static bool operator >(DecimalWrapper a, DecimalWrapper b)
		{
			return a._value > b._value;
		}

		public static bool operator <=(DecimalWrapper a, DecimalWrapper b)
		{
			return a._value <= b._value;
		}

		public static bool operator >=(DecimalWrapper a, DecimalWrapper b)
		{
			return a._value >= b._value;
		}

		bool ILinearScalar.IsGreaterThan(ILinearScalar value) { return this > (DecimalWrapper)value; }
		bool ILinearScalar.IsSmallerThan(ILinearScalar value) { return this < (DecimalWrapper)value; }
		#endregion

		#region IComparable
		int IComparable.CompareTo(object obj)
		{
			DecimalWrapper b = (DecimalWrapper)obj;
			if (this._value < b._value)
				return -1;
			if (this._value > b._value)
				return 1;
			return 0;
		}
		#endregion
	}
}
